package com.zmn.plat.business.impl.channel.brand.ratio;

import java.util.*;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import com.zmn.common.utils.number.NumberUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.utils.collection.CollectionUtil;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.plat.business.interfaces.channel.ChannelBService;
import com.zmn.plat.business.interfaces.channel.brand.ratio.ChannelBrandRatioBService;
import com.zmn.plat.common.constant.ProductConsts;
import com.zmn.plat.common.dictionary.BaseBrandRatioTypeEnum;
import com.zmn.plat.common.dictionary.ChannelBrandRatioTypeEnum;
import com.zmn.plat.common.dictionary.ProductDict;
import com.zmn.plat.common.exception.PlatException;
import com.zmn.plat.model.entity.brand.BaseBrand;
import com.zmn.plat.model.entity.category.BaseCategory;
import com.zmn.plat.model.entity.channel.brand.ratio.ChannelBrandRatio;
import com.zmn.plat.model.entity.channel.brand.ratio.ChannelBrandRatioQuery;
import com.zmn.plat.model.entity.servcategory.ServCategory;
import com.zmn.plat.model.vo.channel.brand.ratio.ChannelBrandCategoryRatioVo;
import com.zmn.plat.model.vo.channel.brand.ratio.ChannelBrandRatioModifyVo;
import com.zmn.plat.model.vo.channel.brand.ratio.ChannelBrandRatioVo;
import com.zmn.plat.services.interfaces.brand.BaseBrandService;
import com.zmn.plat.services.interfaces.category.BaseCategoryService;
import com.zmn.plat.services.interfaces.channel.brand.ratio.ChannelBrandRatioService;
import com.zmn.plat.services.interfaces.servcategory.ServAssCategoryService;
import com.zmn.plat.services.interfaces.servcategory.ServCategoryService;

/**
 * 渠道品牌系数BServiceImpl
 * 
 * @author linfeng
 * @since 2020/09/02 15:05
 */
@Service
public class ChannelBrandRatioBServiceImpl implements ChannelBrandRatioBService {
    private Logger logger = LoggerFactory.getLogger(ChannelBrandRatioBServiceImpl.class);

    @Resource
    ChannelBrandRatioService brandRatioService;
    @Resource
    ServAssCategoryService servAssCategoryService;
    @Resource
    BaseCategoryService baseCategoryService;
    @Resource
    ServCategoryService servCategoryService;
    @Resource
    BaseBrandService baseBrandService;
    @Resource
    ChannelBService channelBService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    @SuppressWarnings("Duplicates")
    public Integer addEditBrandRatio(String mcStaffName, ChannelBrandRatioVo brandRatioVo) {
        Date now = DateUtil.getNow();

        ChannelBrandRatioQuery brandRatioQuery = new ChannelBrandRatioQuery();
        brandRatioQuery.setBrandId(brandRatioVo.getBrandId());
        brandRatioQuery.setChannelId(brandRatioVo.getChannelId());
        brandRatioQuery.setRatioType(ChannelBrandRatioTypeEnum.BRANDRATIO.getCode());
        brandRatioQuery.setPriceType(brandRatioVo.getPriceType());
        brandRatioQuery.setBizType(brandRatioVo.getBizType());
        List<ChannelBrandRatio> brandRatios = brandRatioService.listByQuery(brandRatioQuery);

        // 新增的时候需要判断品牌是否已经添加过系数
        if (brandRatios != null && brandRatios.size() > 0 && brandRatioVo.getAddFlag()) {
            BaseBrand baseBrand = baseBrandService.findByKey(brandRatioVo.getBrandId());
            String brandName = baseBrand == null ? "" : baseBrand.getName();
            logger.error("已存在【{}】品牌，请在对应的品牌下设置品牌系数！", brandName);
            throw new PlatException("已存在【" + brandName + "】品牌，请在对应的品牌下设置品牌系数！");
        }


        try {
            Integer bizType = brandRatioVo.getBizType();
            if (bizType == ProductConsts.BIZ_TYPE_C) {
                // C类业务价格系数时新增修改计价器3.0默认系数
                brandRatioQuery.setBizType(null);
                brandRatioQuery.setRatioType(ChannelBrandRatioTypeEnum.BRANDMETER3RATIO.getCode());
                List<ChannelBrandRatio> brandRatioMeterList = brandRatioService.listByQuery(brandRatioQuery);
                // 新增的时候需要判断品牌是否已经添加过系数
                if (brandRatioMeterList != null && brandRatioMeterList.size() > 0 && brandRatioVo.getAddFlag()) {
                    BaseBrand baseBrand = baseBrandService.findByKey(brandRatioVo.getBrandId());
                    String brandName = baseBrand == null ? "" : baseBrand.getName();
                    logger.error("已存在【{}】品牌，请在对应的品牌下设置计价器3.0品牌系数！", brandName);
                    throw new PlatException("已存在【" + brandName + "】品牌，请在对应的品牌下设置计价器3.0品牌系数！");
                }
                ChannelBrandRatio brandRatioM = null;
                if (CollectionUtil.isNotNullOrEmpty(brandRatioMeterList)) {
                    brandRatioM = brandRatioMeterList.get(0);
                }
                Double meterToBeEffectiveRatio = brandRatioVo.getMeterToBeEffectiveRatio();
                if (brandRatioM == null) {
                    if (NumberUtil.isNotNullOrZero(meterToBeEffectiveRatio)) {
                        ChannelBrandRatio createBrandRatio = new ChannelBrandRatio();
                        BeanUtils.copyProperties(brandRatioVo, createBrandRatio);
                        createBrandRatio.setToBeEffectiveRatio(brandRatioVo.getMeterToBeEffectiveRatio());
                        createBrandRatio.setEffectiveDate(brandRatioVo.getEffectiveDate());
                        createBrandRatio.setCreater(mcStaffName);
                        createBrandRatio.setCreateTime(now);
                        createBrandRatio.setUpdater(mcStaffName);
                        createBrandRatio.setUpdateTime(now);
                        createBrandRatio.setRatioType(ChannelBrandRatioTypeEnum.BRANDMETER3RATIO.getCode());
                        createBrandRatio.setBizType(null);
                        brandRatioService.insert(createBrandRatio);
                    }
                } else {
                    if (NumberUtil.isNullOrZero(brandRatioM.getRatio()) && NumberUtil.isNullOrZero(meterToBeEffectiveRatio)) {
                        brandRatioService.deleteByPrimaryKey(brandRatioM.getRatioId());
                    } else {
                        brandRatioM.setToBeEffectiveRatio(brandRatioVo.getMeterToBeEffectiveRatio());
                        brandRatioM.setEffectiveDate(brandRatioVo.getEffectiveDate());
                        brandRatioM.setUpdateTime(DateUtil.getNow());
                        brandRatioM.setUpdater(mcStaffName);
                        brandRatioService.updateByKey(brandRatioM);
                    }
                }
                channelBService.createLog(brandRatioVo.getChannelId(), null, "渠道品牌计价器3.0系数", null);
            }


            ChannelBrandRatio brandRatio = null;
            if (CollectionUtil.isNotNullOrEmpty(brandRatios)) {
                brandRatio = brandRatios.get(0);
            }
            if (brandRatio == null) {
                if (brandRatioVo.getToBeEffectiveRatio() != null) {
                    ChannelBrandRatio createBrandRatio = new ChannelBrandRatio();
                    BeanUtils.copyProperties(brandRatioVo, createBrandRatio);
                    createBrandRatio.setToBeEffectiveRatio(brandRatioVo.getToBeEffectiveRatio());
                    createBrandRatio.setEffectiveDate(brandRatioVo.getEffectiveDate());
                    createBrandRatio.setCreater(mcStaffName);
                    createBrandRatio.setCreateTime(now);
                    createBrandRatio.setUpdater(mcStaffName);
                    createBrandRatio.setUpdateTime(now);
                    createBrandRatio.setRatioType(ChannelBrandRatioTypeEnum.BRANDRATIO.getCode());
                    brandRatioService.insert(createBrandRatio);
                }
            } else {
                if (brandRatio.getRatio() == null && brandRatioVo.getToBeEffectiveRatio() == null) {
                    brandRatioService.deleteByPrimaryKey(brandRatio.getRatioId());
                } else {
                    brandRatio.setToBeEffectiveRatio(brandRatioVo.getToBeEffectiveRatio());
                    brandRatio.setEffectiveDate(brandRatioVo.getEffectiveDate());
                    brandRatio.setUpdateTime(DateUtil.getNow());
                    brandRatio.setUpdater(mcStaffName);
                    brandRatioService.updateByKey(brandRatio);
                }
            }

            channelBService.createLog(brandRatioVo.getChannelId(), null, ProductDict.getBizTypeCNENName(brandRatioVo.getBizType()), null);

            return brandRatioVo.getBrandId();
        } catch (Exception ex) {
            throw new PlatException(ex.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @SuppressWarnings("Duplicates")
    public Integer addEditCategoryRatio(String mcStaffName, ChannelBrandRatioModifyVo brandRatioModifyVo) {
        Date now = DateUtil.getNow();
        Integer channelId = brandRatioModifyVo.getCategOneBrandRatio().getChannelId();
        Integer brandId = brandRatioModifyVo.getCategOneBrandRatio().getBrandId();
        Integer priceType = brandRatioModifyVo.getCategOneBrandRatio().getPriceType();
        Integer bizType = brandRatioModifyVo.getCategOneBrandRatio().getBizType();
        Integer servCategId = brandRatioModifyVo.getCategOneBrandRatio().getServCategId();
        Integer categOneId = brandRatioModifyVo.getCategOneBrandRatio().getCategOneId();
        ChannelBrandRatio categOneRatioResult = null;
        ChannelBrandRatioQuery query = new ChannelBrandRatioQuery();
        query.setChannelId(channelId);
        query.setBrandId(brandId);
        query.setServCategId(servCategId);
        query.setBizType(bizType);
        query.setPriceType(priceType);
        query.setCategOneId(categOneId);
        query.setRatioType(ChannelBrandRatioTypeEnum.BRANDCATEGONERATIO.getCode());
        List<ChannelBrandRatio> categOneRatios = brandRatioService.listByQuery(query);
        if (categOneRatios != null && categOneRatios.size() > 0) {
            categOneRatioResult = categOneRatios.get(0);
        }
        Double categOneRatio = brandRatioModifyVo.getCategOneBrandRatio().getToBeEffectiveRatio();

        // 处理一级分类系数
        if (categOneRatioResult == null) {
            if (categOneRatio != null) {
                ChannelBrandRatio createOneRatio = new ChannelBrandRatio();
                createOneRatio = brandRatioModifyVo.getCategOneBrandRatio();
                createOneRatio.setCreater(mcStaffName);
                createOneRatio.setUpdater(mcStaffName);
                createOneRatio.setCreateTime(now);
                createOneRatio.setUpdateTime(now);
                createOneRatio.setRatioType(BaseBrandRatioTypeEnum.BRANDCATEGONERATIO.getCode());
                brandRatioService.insert(createOneRatio);
            }
        } else {
            if (categOneRatioResult.getRatio() == null && categOneRatio == null) {
                brandRatioService.deleteByPrimaryKey(categOneRatioResult.getRatioId());
            } else {
                categOneRatioResult.setToBeEffectiveRatio(categOneRatio);
                categOneRatioResult.setEffectiveDate(brandRatioModifyVo.getCategOneBrandRatio().getEffectiveDate());
                categOneRatioResult.setUpdateTime(DateUtil.getNow());
                categOneRatioResult.setUpdater(mcStaffName);
                brandRatioService.updateByKey(categOneRatioResult);
            }
        }

        // 处理二级分类系数
        query.setRatioType(ChannelBrandRatioTypeEnum.BRANDCATEGTWORATIO.getCode());
        List<ChannelBrandRatio> dbCategTwoRatios = brandRatioService.listByQuery(query);

        ChannelBrandRatioQuery brandRatioQuery = new ChannelBrandRatioQuery();
        BeanUtils.copyProperties(query, brandRatioQuery);
        List<ChannelBrandRatio> categTwoRatios = brandRatioModifyVo.getCategTwoBrandRatioList();
        List<ChannelBrandRatio> insertRatioList = new ArrayList<>();
        List<Integer> deleteRatioList = new ArrayList<>();
        List<ChannelBrandRatio> updateRatioList = new ArrayList<>();
        if (categTwoRatios != null && categTwoRatios.size() > 0) {
            categTwoRatios.forEach(e -> {
                brandRatioQuery.setCategId(e.getCategId());
                ChannelBrandRatio dbRatio = findBrandRatioByQueryOfCategTwoRatioList(brandRatioQuery, dbCategTwoRatios);

                if (dbRatio == null) {
                    if (e.getToBeEffectiveRatio() != null) {
                        e.setRatioType(ChannelBrandRatioTypeEnum.BRANDCATEGTWORATIO.getCode());
                        e.setCreater(mcStaffName);
                        e.setUpdater(mcStaffName);
                        e.setCreateTime(now);
                        e.setUpdateTime(now);
                        insertRatioList.add(e);
                    }
                } else {
                    if (dbRatio.getRatio() == null && e.getToBeEffectiveRatio() == null) {
                        deleteRatioList.add(dbRatio.getRatioId());
                    } else {
                        e.setUpdateTime(DateUtil.getNow());
                        e.setUpdater(mcStaffName);
                        e.setRatioId(dbRatio.getRatioId());
                        updateRatioList.add(e);
                    }
                }
            });

            if (CollectionUtil.isNotNullOrEmpty(insertRatioList)) {
                brandRatioService.insertBatch(insertRatioList);
            }
            if (CollectionUtil.isNotNullOrEmpty(deleteRatioList)) {
                brandRatioService.deleteByKeys(deleteRatioList);
            }
            if (CollectionUtil.isNotNullOrEmpty(updateRatioList)) {
                brandRatioService.updateToBeEffectiveRatioBatch(updateRatioList);
            }
        }

        channelBService.createLog(channelId, null, ProductDict.getBizTypeCNENName(bizType), null);

        return GlobalConsts.YES;
    }

    @Override
    @SuppressWarnings("Duplicates")
    public ChannelBrandCategoryRatioVo findByChannelIdAndBrandIdAndServCategId(int channelId, int brandId, int priceType, int servCategId, int bizType) {
        ChannelBrandRatioQuery brandRatioQuery = new ChannelBrandRatioQuery();
        brandRatioQuery.setChannelId(channelId);
        brandRatioQuery.setBrandId(brandId);
        brandRatioQuery.setBizType(bizType);
        brandRatioQuery.setRatioType(ChannelBrandRatioTypeEnum.BRANDCATEGONERATIO.getCode());
        brandRatioQuery.setPriceType(priceType);
        brandRatioQuery.setServCategId(servCategId);

        List<ServCategory> servCategoryList = servAssCategoryService.findServCategoryByBrandIdAndShowType(brandId, ProductConsts.ERP_PRODUCT_TYPE);
        String servCategName = "";
        if (servCategId == 0) {
            if (CollectionUtil.isNotNullOrEmpty(servCategoryList)) {
                ServCategory servCategory = servCategoryList.get(0);
                brandRatioQuery.setServCategId(servCategory.getCategId());
                servCategName = servCategory.getName();
            }
        } else {
            ServCategory servCategory = servCategoryService.findByKey(servCategId);
            servCategName = servCategory.getName();
        }

        List<ChannelBrandRatio> brandLevelOneRatioVos = brandRatioService.listByQuery(brandRatioQuery);
        brandRatioQuery.setRatioType(ChannelBrandRatioTypeEnum.BRANDCATEGTWORATIO.getCode());
        List<ChannelBrandRatio> brandLevelTwoRatioVos = brandRatioService.listByQuery(brandRatioQuery);

        List<BaseCategory> categTwos = Optional.ofNullable(servAssCategoryService.findCategoryTwoByServIdAndBrandIdAndShowType(brandRatioQuery.getServCategId(), brandId, ProductConsts.ERP_PRODUCT_TYPE)).orElse(Collections.EMPTY_LIST);

        Map<Integer, List<BaseCategory>> map = categTwos.stream().collect(Collectors.groupingBy(BaseCategory::getParentId));
        Map<Integer, List<ChannelBrandRatioVo>> levelTwoRatioMap = new HashMap<>();
        for (Map.Entry<Integer, List<BaseCategory>> entry : map.entrySet()) {
            List<ChannelBrandRatioVo> resultList = new ArrayList<>();
            if (entry.getValue() != null) {
                for (BaseCategory baseCategory : entry.getValue()) {
                    ChannelBrandRatioVo brandLevelTwoRatioVo = new ChannelBrandRatioVo();
                    brandLevelTwoRatioVo.setBrandId(brandId);
                    brandLevelTwoRatioVo.setCategOneId(entry.getKey());
                    brandLevelTwoRatioVo.setCategId(baseCategory.getCategId());
                    brandLevelTwoRatioVo.setCategName(baseCategory.getName());
                    for (ChannelBrandRatio inner : brandLevelTwoRatioVos) {
                        if (inner.getCategId().equals(baseCategory.getCategId()) && inner.getCategOneId().equals(baseCategory.getParentId())) {
                            brandLevelTwoRatioVo.setRatio(inner.getRatio());
                            brandLevelTwoRatioVo.setToBeEffectiveRatio(inner.getToBeEffectiveRatio());
                        }
                    }
                    resultList.add(brandLevelTwoRatioVo);
                }
            }
            levelTwoRatioMap.put(entry.getKey(), resultList);
        }

        List<Integer> categOneIds = categTwos.stream().map(e -> e.getParentId()).distinct().collect(Collectors.toList());

        List<BaseCategory> categOnes = new ArrayList<>();
        if (CollectionUtil.isNotNullOrEmpty(categOneIds)) {
            categOnes = baseCategoryService.findByKeys(categOneIds);
        }

        List<ChannelBrandRatioVo> constructVo = new ArrayList<>();
        for (BaseCategory baseCategory : categOnes) {
            ChannelBrandRatioVo brandLevelOneRatioVo = new ChannelBrandRatioVo();
            brandLevelOneRatioVo.setCategOneId(baseCategory.getCategId());
            brandLevelOneRatioVo.setCategName(baseCategory.getName());
            constructVo.add(brandLevelOneRatioVo);
        }

        for (ChannelBrandRatioVo brandLevelOneRatioVo : constructVo) {
            for (ChannelBrandRatio inner : brandLevelOneRatioVos) {
                if (brandLevelOneRatioVo.getCategOneId().equals(inner.getCategOneId())) {
                    brandLevelOneRatioVo.setRatio(inner.getRatio());
                    brandLevelOneRatioVo.setToBeEffectiveRatio(inner.getToBeEffectiveRatio());
                }
            }
        }

        ChannelBrandCategoryRatioVo channelBrandCategoryRatioVo = new ChannelBrandCategoryRatioVo();
        channelBrandCategoryRatioVo.setServCategId(brandRatioQuery.getServCategId());
        channelBrandCategoryRatioVo.setServCategName(servCategName);
        channelBrandCategoryRatioVo.setServCategories(servCategoryList);
        channelBrandCategoryRatioVo.setBrandLevelOneRatioVos(constructVo);
        channelBrandCategoryRatioVo.setMap(levelTwoRatioMap);

        return channelBrandCategoryRatioVo;
    }

    @Override
    @SuppressWarnings("Duplicates")
    public List<ChannelBrandRatioVo> listBrandLevelTwoRatioVo(ChannelBrandRatioQuery query) {
        List<ChannelBrandRatio> brandLevelTwoRatioVos = brandRatioService.listByQuery(query);
        List<BaseCategory> categTwos = servAssCategoryService.findCategoryTwoByServIdAndShowType(query.getServCategId(), ProductConsts.ERP_PRODUCT_TYPE);
        Map<Integer, List<BaseCategory>> map = categTwos.stream().collect(Collectors.groupingBy(BaseCategory::getParentId));

        List<ChannelBrandRatioVo> resultList = new ArrayList<>();
        if (map.get(query.getCategOneId()) != null) {
            for (BaseCategory baseCategory : map.get(query.getCategOneId())) {
                ChannelBrandRatioVo brandLevelTwoRatioVo = new ChannelBrandRatioVo();
                brandLevelTwoRatioVo.setBrandId(query.getBrandId());
                brandLevelTwoRatioVo.setCategOneId(query.getCategOneId());
                brandLevelTwoRatioVo.setCategId(baseCategory.getCategId());
                brandLevelTwoRatioVo.setCategName(baseCategory.getName());
                for (ChannelBrandRatio inner : brandLevelTwoRatioVos) {
                    if (inner.getCategId().equals(baseCategory.getCategId()) && inner.getCategOneId().equals(baseCategory.getParentId())) {
                        brandLevelTwoRatioVo.setRatio(inner.getRatio());
                        brandLevelTwoRatioVo.setToBeEffectiveRatio(inner.getToBeEffectiveRatio());
                    }
                }
                resultList.add(brandLevelTwoRatioVo);
            }
        }

        return resultList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void copyRatio(Integer sourceChannelId, Integer targetChannelId, Integer bizType, Integer priceType, Date effectiveDate, String opertor) {
        brandRatioService.deleteByChannelIdAndPriceTypeAndBizType(targetChannelId, priceType, bizType);
        brandRatioService.copyRatio(sourceChannelId, targetChannelId, bizType, priceType, effectiveDate, opertor);
        channelBService.createLog(targetChannelId, null, ProductDict.getBizTypeCNENName(bizType), null);
    }

    @SuppressWarnings("Duplicates")
    private ChannelBrandRatio findBrandRatioByQueryOfCategTwoRatioList(ChannelBrandRatioQuery brandRatioQuery, List<ChannelBrandRatio> categTwoRatioList) {
        ChannelBrandRatio brandRatio;
        for (int i = 0; i < categTwoRatioList.size(); i++) {
            brandRatio = categTwoRatioList.get(i);
            if (Objects.equals(brandRatioQuery.getBrandId(), brandRatio.getBrandId()) && Objects.equals(brandRatioQuery.getServCategId(), brandRatioQuery.getServCategId())
                && Objects.equals(brandRatioQuery.getCategOneId(), brandRatio.getCategOneId()) && Objects.equals(brandRatioQuery.getCategId(), brandRatio.getCategId())
                && Objects.equals(brandRatioQuery.getBizType(), brandRatio.getBizType()) && Objects.equals(brandRatioQuery.getPriceType(), brandRatio.getPriceType())
                && Objects.equals(brandRatioQuery.getRatioType(), brandRatio.getRatioType()) && Objects.equals(brandRatioQuery.getChannelId(), brandRatio.getChannelId())) {
                return brandRatio;
            }
        }
        return null;
    }

}
